package com.portal.redis.lock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * redis分布式锁
 * 控制集群服务器同一时间内只有一台执行任务:校准服务器之间的时间误差
 *
 * @author Amadeus
 * @date 2022/07/07
 */
@Component("redisDistributedLock")
public class RedisDistributedLock implements DistributedLock {
    private static final Logger LOGGER = LoggerFactory.getLogger(RedisDistributedLock.class);

    /**
     * 分布式锁的前缀
     */
    private static final String LOCK_PREFIX = "lock:";
    /**
     * 分布式锁的有效时间s(秒),不能超过定时任务执行的时间差,防止第二次执行任务key还存在
     */
    private static final long LOCK_EXPIRE_TIME = 15;
    /**
     * 请求分布式锁的超时时间ms(毫秒)
     */
    private static final long TIME_OUT = 100;


    @Resource
    public RedisTemplate<String, Object> redisTemplate;

    @Override
    public Boolean lock(String key) {
        return lock(key, LOCK_EXPIRE_TIME);
    }


    @Override
    public Boolean lock(String key, Long expireTime) {
        Boolean lock = false;
        long currentTime = System.currentTimeMillis();
        while (System.currentTimeMillis() - currentTime < TIME_OUT) {
            try {
                lock = redisTemplate.opsForValue().setIfAbsent(LOCK_PREFIX + key, String.valueOf(Thread.currentThread().getId()), expireTime, TimeUnit.SECONDS);
                if (lock != null) {
                    return lock;
                }
            } catch (Exception e) {
                LOGGER.error("taskId -> {} 请求redis分布式锁出现异常", key, e);
            }
        }
        return lock;
    }

    /**
     * 这里并未校验是不是自己的锁
     *
     * @param key
     */
    @Override
    public void unLock(String key) {
        try {
            redisTemplate.delete(key);
        } catch (Exception e) {
            LOGGER.error("taskId -> {} 解除redis分布式锁出现异常", key, e);
        }
    }
}
